/*******************************************************************************
 * Copyright (c) 2011 Grupo de Sistemas Inteligentes (GSI) - DIT UPM
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/
package es.upm.dit.gsi.eclipse.jadex.adfmanager.wizards;

import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWizard;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.operation.*;

import java.io.File;
import java.lang.reflect.InvocationTargetException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.core.runtime.CoreException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import es.upm.dit.gsi.eclipse.jadex.util.ImageFactory;

/**
 * Wizard for adding a new Belief to the selected agent
 * 
 * It has got 2 pages:
 *  - Page1: Belief type and details
 *  - Page2: Adding fact/s to the belief/set
 *  
 * @author Jorge Valhondo Rama
 */

public class AddBeliefWizard extends Wizard implements INewWizard {
	private AddBeliefWizardPage1 page1;
	private AddBeliefWizardPage2 page2;
	private ISelection selection;

	/**
	 * Constructor for AddBeliefWizard
	 */
	public AddBeliefWizard(ISelection selection) {
		super();
		setNeedsProgressMonitor(true);
		this.selection = selection;
		setDefaultPageImageDescriptor(ImageFactory.getImageDescriptor(ImageFactory.GSI_BANNER_SMALL));
	}
	
	/**
	 * Adding pages to the wizard.
	 */
	public void addPages() {
		page1 = new AddBeliefWizardPage1(selection);
		page1.setTitle("Add Belief Wizard");
		page2 = new AddBeliefWizardPage2(selection);
		page2.setTitle("Add Belief/set Wizard");
		addPage(page1);
		addPage(page2);
	}

	/**
	 * This method is called when 'Finish' button is pressed in
	 * the wizard. We will create an operation and run it
	 * using wizard as execution context.
	 */
	public boolean performFinish() {
		final IFile agentFile = (IFile)((IStructuredSelection)selection).getFirstElement();
		final IFolder sourceFolder = page1.getSourceFolder();
		final String packageName = page1.getPackageName();
		
		//Belief/s attributes
		final String beliefType = page1.getBeliefType();
		final String beliefName = page1.getBeliefName();
		final String beliefClassName = page1.getBeliefClassName();
		final String beliefDescription = page1.getBeliefDescription();
		final String beliefUpDateRate = page1.getBeliefUpDateRate();
		final String beliefTransient = page1.getBeliefTransient();
		final String beliefEvaluationMode = page1.getBeliefEvaluationMode();
		
		//Belief/set fact/s
		final Fact[] facts = page2.getFacts();
		
		IRunnableWithProgress op = new IRunnableWithProgress() {
			public void run(IProgressMonitor monitor) throws InvocationTargetException {
				try {
					doFinish(agentFile, sourceFolder, packageName, beliefType, beliefName, beliefClassName, beliefDescription,
							beliefUpDateRate, beliefTransient, beliefEvaluationMode, facts, monitor);
				} catch (CoreException e) {
					throw new InvocationTargetException(e);
				} finally {
					monitor.done();
				}
			}
		};
		
		try {
			getContainer().run(true, false, op);
		} catch (InterruptedException e) {
			return false;
		} catch (InvocationTargetException e) {
			Throwable realException = e.getTargetException();
			MessageDialog.openError(getShell(), "Error", realException.getMessage());
			return false;
		}
		return true;
	}
	
	/**
	 * The worker method. It will add the necessary information to the ADF file in 
	 * order to configure the new Belief.
	 */
	private void doFinish(
			IFile agentFile,
			IFolder sourceFolder,
			String packageName,
			String beliefType,
			String beliefName,
			String beliefClassName,
			String beliefDescription,
			String beliefUpDateRate,
			String beliefTransient,
			String beliefEvaluationMode,
			Fact[] facts,
			IProgressMonitor monitor)
		throws CoreException {
		
		monitor.beginTask("Modificating ADF File", 2);
		
		try{
		DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
		Document doc = docBuilder.parse(agentFile.getRawLocation().toOSString());
	 
		//Get the beliefs element 
		Node beliefs = doc.getElementsByTagName("beliefs").item(0);
		
		Element newBelief = doc.createElement(beliefType);
		newBelief.setAttribute("name", beliefName);
		newBelief.setAttribute("class", beliefClassName);
		
		//Set the attributes for the new belief
		if(beliefDescription != null) newBelief.setAttribute("description", beliefDescription);
		if(beliefUpDateRate != null) newBelief.setAttribute("updaterate", beliefUpDateRate);
		if(beliefTransient != null) newBelief.setAttribute("transient", beliefTransient);
		if(beliefEvaluationMode != null) newBelief.setAttribute("evaluationmode", beliefEvaluationMode);
		
		//Set the fact/s for the belief/set
		if(facts != null){
			for(Fact f : facts){
				Element fact = doc.createElement("parameter");
				fact.setAttribute("name", f.get_name());
				fact.setAttribute("class", f.get_class());
				fact.setAttribute("description", f.get_description());
				fact.setAttribute("language", f.get_language());
				
				newBelief.appendChild(fact);
			}
		}
		beliefs.appendChild(newBelief);
		
		//write the content into xml file
	    
		TransformerFactory transformerFactory = TransformerFactory.newInstance();
	    transformerFactory.setAttribute("indent-number", new Integer(4));
	    Transformer transformer;
		transformer = transformerFactory.newTransformer();
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
	    DOMSource source = new DOMSource(doc);
	    StreamResult result =  new StreamResult(new File(agentFile.getRawLocation().toOSString()));
	    transformer.transform(source, result);
	    agentFile.refreshLocal(IFile.DEPTH_INFINITE, monitor);
		}
		catch(Exception e1){
			e1.printStackTrace();
		}
	    System.out.println("Done");
	    monitor.worked(1);
	}

	/**
	 * We will accept the selection in the workbench to see if
	 * we can initialize from it.
	 * @see IWorkbenchWizard#init(IWorkbench, IStructuredSelection)
	 */
	public void init(IWorkbench workbench, IStructuredSelection selection) {
		this.selection = selection;
	}
}